/***************************************************************************
 *   Copyright (C) 2009 by Zheng Yonglei
 *   zhengyonglei@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QFile>
#include <QTextStream>
#include <QFileDialog>
#include <QStringList>
#include <QTextCodec>

#include "MessageBox.h"
#include "DictMaker.h"
#include "SQLiteDB.h"
#include "types.h"
#include "Logger.h"
#include "Options.h"

DictMaker::DictMaker(QDialog *parent)
    : QDialog(parent)
{
	ui.setupUi(this);

	QObject::connect(ui.closeButton, SIGNAL(clicked()), this, SLOT(accept()));
	QObject::connect(ui.rawDictFileBrowseButton, SIGNAL(clicked()), this, SLOT(selectRawDictFile()));
	QObject::connect(ui.saveDBFileButton, SIGNAL(clicked()), this, SLOT(setSavedDBFile()));
	QObject::connect(ui.convertButton, SIGNAL(clicked()), this, SLOT(convert()));
}

DictMaker::~DictMaker()
{

}

bool DictMaker::parseTxtFile(QString fileName, DictInfo& dictInfo)
{
	OPT.setCursorBusy(true);
	LOG<<"fileName="<<fileName<<endl;
	dictInfo.mDictType = "txt";

	//read info file
	QFile file(fileName);
	LOG<<"file="<<file.fileName()<<endl;
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		cout<<"Fail to open dictFile "<<file.fileName().toUtf8().data()<<endl;
		return false;
	}

	while (!file.atEnd())
	{
		QByteArray line_b = file.readLine();
		QTextCodec* codec = QTextCodec::codecForName("UTF8");
		QString line = codec->toUnicode(line_b);

		line = line.simplified();
		if (line.contains("bookname="))
			dictInfo.mDictName = line.remove("bookname=").simplified();
		if (line.contains("description="))
			dictInfo.mDictDescription = line.remove("description=").simplified();
	}
	file.close();
	QString fileNoFormat = file.fileName().left(file.fileName().lastIndexOf("."));
	LOG<<"fileNoFormat="<<fileNoFormat<<endl;

	//read article file
	file.setFileName(fileNoFormat + ".txt");
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		cout<<"Fail to open dictFile "<<file.fileName().toUtf8().data()<<endl;
		return false;
	}
	LOG<<"file="<<file.fileName()<<endl;

	int count=0;
	QString lastKey;
	while (!file.atEnd())
	{
		count++;
		if (count%10000 == 0)
			LOG<<count<<" words parsed."<<endl;

		QByteArray line_b = file.readLine();
		QByteArray termSign("\\0");
		line_b.replace('\0', QByteArray(termSign));
		QTextCodec* codec = QTextCodec::codecForName("UTF8");
		QString line = codec->toUnicode(line_b);
		line.remove(termSign);
		int EnglishEnd = line.indexOf('\t');
		QString key = line.left(EnglishEnd);
		key.replace(QString("\'"), QString("\'\'"));
		QString article = line.right(line.size() - EnglishEnd);
		while (article.contains("<IMG SRC"))
		{
			int imgTagStartPos = article.indexOf("<IMG SRC");
			int imgTagEndPos = article.indexOf(">", imgTagStartPos);
			article.remove(imgTagStartPos, imgTagEndPos - imgTagStartPos + 1);
		}
		article.replace(QString("\'"), QString("\'\'"));

		if (key == lastKey)
		{
			LOG<<"key == lastKey = "<<lastKey<<endl;
			mDictInfo.articles.last().append(QString("<br><br>") + article);
		}
		else
		{
			mDictInfo.keys<<key;
			mDictInfo.articles<<article;
		}

		lastKey = key;
	}

	OPT.setCursorBusy(false);
	return true;
}

bool DictMaker::parseXdxfFile(QString fileName, DictInfo& dictInfo)
{
	OPT.setCursorBusy(true);
	LOG<<"fileName="<<fileName<<endl;
	dictInfo.mDictType = "xdxf";

	QFile file(fileName);
	if (file.open(QIODevice::ReadOnly))
		LOG<<"The file "<<fileName.toUtf8().data()<<" is opened successfully."<<endl;
	else
	{
		OPT.setCursorBusy(false);
		LOG<<"Open file "<<fileName.toUtf8().data()<<" failed."<<endl;
		return false;
	}

	QDomDocument xdxfDocument;
	QDomElement xdxfRootNode;
	QDomElement xdxfCurNode;

	QString xdxfStr;
	while (!file.atEnd())
	{
		QByteArray line = file.readLine();
		QTextCodec* codec = QTextCodec::codecForName("UTF8");
		xdxfStr.append(codec->toUnicode(line));
		xdxfStr.append("<!--br-->");
	}

	if (xdxfDocument.setContent(xdxfStr))
	{
		LOG<<"The file "<<fileName.toUtf8().data()<<" is parsed successfully."<<endl;
	}
	else
	{
		OPT.setCursorBusy(false);
		LOG<<"Parse file "<<fileName.toUtf8().data()<<" failed."<<endl;
		QString msg(QString("Parse xdxf file \"%1\" error. ").arg(fileName));
		MessageBox::showWarning(QMessageBox::Warning, "Error!", msg, 12);
		return false;
	}

	QString command;
	QString dictFullName;
	QString dictDiscription;
	xdxfRootNode = xdxfDocument.documentElement();
	QDomNodeList nodeList = xdxfRootNode.childNodes();
	for (int i=0; i<nodeList.size(); i++)
	{
		if (nodeList.item(i).toElement().tagName() == QString("full_name"))
		{
			dictInfo.mDictName = nodeList.item(i).toElement().text().replace(QString("\'"), QString("\'\'"));
			continue;
		}

		if (nodeList.item(i).toElement().tagName() == QString("description"))
		{
			dictInfo.mDictDescription = nodeList.item(i).toElement().text().replace(QString("\'"), QString("\'\'"));
			continue;
		}

		if (nodeList.item(i).toElement().tagName() == QString("ar"))
		{
			QString article;
			QTextStream articleStream;
			articleStream.setString(&article);
			nodeList.item(i).save(articleStream,-1);
			article.replace(QString("\'"), QString("\'\'"));
			article.replace(QString("<!--br-->"), QString("<br>"));

			QDomNodeList contentNodes =  nodeList.item(i).childNodes();
			QString lastKey;
			for (int j=0; j<contentNodes.size(); j++)
			{
				if (contentNodes.item(j).toElement().tagName() == QString("k"))
				{
					QString key = contentNodes.item(j).toElement().text().replace(QString("\'"), QString("\'\'"));;
					key.replace(QString("\'"), QString("\'\'"));
					if (j == 0)
					{
						lastKey = key;
						dictInfo.keys<<key;
						dictInfo.articles<<article;
					}
					else
					{
						QString linkInfo = QString("<key_link>%1</key_link>").arg(lastKey);
						dictInfo.keys<<key;
						dictInfo.articles<<linkInfo;
					}
				}
			}
			continue;
		}
	}

	assert(dictInfo.keys.size() == dictInfo.articles.size());
	OPT.setCursorBusy(false);

	QString msg(QString("Xdxf file \"%1\" is parsed successfully. ").arg(fileName));
	MessageBox::showConfirm(QMessageBox::Information, "OK!", msg, 12);

	return true;
}

void DictMaker::selectRawDictFile()
{
	QFileDialog fileDialog(this,
			tr("Select dictionary file to be converted (xdxf or stardict(txt) format)"), ".",
			tr("Files (*.xdxf *.ifo)"));
	fileDialog.exec();
	QStringList fileList = fileDialog.selectedFiles();
	if (fileList.isEmpty())
		return;

	QString fileName = fileList.first();
	fileName = fileName.simplified();
	if (fileName.isEmpty())
		return;

	ui.dictRawFilePathEditor->setText(fileName);
	LOG<<"fileName="<<fileName<<endl;
	QString format = fileName.right(fileName.size() - fileName.lastIndexOf(".") - 1);
	LOG<<"format="<<format<<endl;

	mDictInfo.clear();
	if (format.compare("ifo", Qt::CaseInsensitive) == 0)
	{
		if (!parseTxtFile(fileName, mDictInfo))
			return;
	}
	else if (format.compare("xdxf", Qt::CaseInsensitive) == 0)
	{
		if (!parseXdxfFile(fileName, mDictInfo))
			return;
	}
	else
		LOG<<"Unexpected format \""<<format<<"\""<<endl;

	ui.dictInfoBrowser->clear();
	QString dictInfoStr;
	QTextStream ds(&dictInfoStr);
	ds<<"<font color='blue'>Name: </font>"<<mDictInfo.mDictName<<"<br>";
	ds<<"<font color='blue'>Description: </font>"<<mDictInfo.mDictDescription<<"<br>";
	ds<<"<font color='blue'>Word count: </font>"<<mDictInfo.keys.size()<<"<br>";
	ui.dictInfoBrowser->insertHtml(dictInfoStr);
}

void DictMaker::setSavedDBFile()
{
	QFileDialog fileDialog(this,
			tr("Save dictionary database as (*.db)"), DICT_DIR,
			tr("Dictionary database (*.db)"));
	fileDialog.setAcceptMode(QFileDialog::AcceptSave);
	fileDialog.exec();
	QStringList fileList = fileDialog.selectedFiles();
	if (fileList.isEmpty())
		return;

	QString fileName = fileList.first();
	//LOG<<"fileName="<<fileName<<endl;
	QString format = fileName.right(fileName.size() - fileName.lastIndexOf(".") - 1);
	QString dbName = fileName.right(fileName.size() - fileName.lastIndexOf(".") - 1);
	if (format != "db")
		fileName.append(".db");
	ui.savedDBFileEditor->setText(fileName);
}

void DictMaker::convert()
{
	OPT.setCursorBusy(true);
	QString dbFileName = ui.savedDBFileEditor->text();
	dbFileName = dbFileName.simplified();
	if (dbFileName.isEmpty())
		return;
	//LOG<<"dbFileName="<<dbFileName<<endl;
	QString dbName("temp");
	SQLiteDB db;
	if (!db.openDB(dbFileName, dbName, true))
	{
		LOG<<"Fail to open database "<<dbName.toUtf8().data()<<endl;
		return;
	}
	mDictInfo.mDBName = dbName;
	createEmptyDictDB(db, mDictInfo);

	QString command;
	QTextStream cs(&command);
	cs<<" insert into "
			" dict_info (dict_type,full_name, description) "
			" values('"<<mDictInfo.mDictType<<"','"<<mDictInfo.mDictName<<"', '"<<mDictInfo.mDictDescription<<"');";
	db.execQuery(command, QueryT_Write, mDictInfo.mDBName);

	assert(mDictInfo.keys.size() == mDictInfo.articles.size());
	db.execQuery("BEGIN", QueryT_Write, mDictInfo.mDBName);
	for (int i=0; i<mDictInfo.keys.size(); i++)
	{
		command.clear();
		cs<<" insert into "
				" articles (key, article) "
				" values('"<<mDictInfo.keys[i]<<"', '"<<mDictInfo.articles[i]<<"');";
		//LOG<<"key = "<<mDictInfo.keys[i]<<endl;
		db.execQuery(command, QueryT_Write, mDictInfo.mDBName);
	}
	db.execQuery("COMMIT", QueryT_Write, mDictInfo.mDBName);
	OPT.setCursorBusy(false);

	QString dictInfoStr;
	QTextStream ds(&dictInfoStr);
	ds<<"<br>The dictionary database \""<<dbFileName<<"\" is created successfully. Please restart the application to load it.<br>";
	ui.dictInfoBrowser->insertHtml(dictInfoStr);

	QString msg(QString("The dictionary database \"%1\" is generated successfully. ").arg(dbFileName));
	MessageBox::showConfirm(QMessageBox::Information, "OK!", msg, 12);
}

void DictMaker::createEmptyDictDB(SQLiteDB& db, DictInfo& dictInfo)
{
	QStringList dictInfoCols;
	dictInfoCols.push_back("dict_type text");
	dictInfoCols.push_back("full_name text");
	dictInfoCols.push_back("description text ");

	db.createEmptyTable(dictInfo.mDBName, "dict_info", dictInfoCols);

	QStringList articleCols;
	articleCols.push_back("key text primary key ");
	articleCols.push_back("article text ");
	db.createEmptyTable(dictInfo.mDBName, "articles", articleCols);
}
